/*
 *
 *  * | Licensed 未经许可不能去掉「OPENIITA」相关版权
 *  * +----------------------------------------------------------------------
 *  * | Author: xw2sy@163.com
 *  * +----------------------------------------------------------------------
 *
 *  Copyright [2024] [OPENIITA]
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 * /
 */

package cc.iotkit.data.service.miniAdmin;

import cc.iotkit.common.api.PageRequest;
import cc.iotkit.common.api.Paging;
import cc.iotkit.common.utils.MapstructUtils;
import cc.iotkit.common.utils.StringUtils;
import cc.iotkit.data.dao.DeviceDistributorDetailRepository;
import cc.iotkit.data.dao.DeviceDistributorRepository;
import cc.iotkit.data.dao.DeviceInfoRepository;
import cc.iotkit.data.dao.IJPACommData;
import cc.iotkit.data.miniAdmin.IDeviceDistributorData;
import cc.iotkit.data.model.*;
import cc.iotkit.data.util.PredicateBuilder;
import cc.iotkit.model.device.DeviceInfo;
import cc.iotkit.model.miniAdmin.*;
import cn.hutool.core.bean.BeanUtil;
import com.querydsl.core.QueryResults;
import com.querydsl.core.Tuple;
import com.querydsl.core.types.Predicate;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import static cc.iotkit.data.model.QTbDeviceDistributor.tbDeviceDistributor;
import static cc.iotkit.data.model.QTbDeviceDistributorDetail.tbDeviceDistributorDetail;
import static cc.iotkit.data.model.QTbDeviceInfo.tbDeviceInfo;
import static cc.iotkit.data.model.QTbSysDistributor.tbSysDistributor;

/**
 * @Author：tfd
 * @Date：2023/5/31 9:45
 */
@Primary
@Service
@RequiredArgsConstructor
public class DeviceDistributorDataImpl
        implements IDeviceDistributorData, IJPACommData<DeviceDistributor, Long> {

    private final DeviceDistributorRepository  deviceDistributorRepository;

    private final DeviceDistributorDetailRepository deviceDistributorDetailRepository;

    private final DeviceInfoRepository deviceInfoRepository;

    private final JPAQueryFactory jpaQueryFactory;

    @Override
    public JpaRepository getBaseRepository() {
        return deviceDistributorRepository;
    }

    @Override
    public Class getJpaRepositoryClass() {
        return TbDeviceDistributor.class;
    }

    @Override
    public Class getTClass() {
        return DeviceDistributor.class;
    }


    @Override
    public Paging<DeviceDistributorDTO> findByConditions(PageRequest<String> pageRequest) {

        // 1. 定义查询实体的Q类
        QTbDeviceDistributor qMain = tbDeviceDistributor;
        QTbDeviceInfo qDeviceInfo = tbDeviceInfo;

        QTbSysDistributor qDistributor = tbSysDistributor;


        String data = pageRequest.getData();
        Predicate predicate = buildQueryCondition(data);

        QueryResults<Tuple> queryResults =
                jpaQueryFactory.select(qMain, qDeviceInfo, qDistributor)  // 同时查询主表和详情表字段
                        .from(qMain)
                        .leftJoin(qDeviceInfo).on(qMain.deviceId.eq(qDeviceInfo.deviceId))
                        .leftJoin(qDistributor).on(qMain.distributorId.eq(qDistributor.id))
                        .where(predicate).offset(pageRequest.getOffset())
                .limit(pageRequest.getPageSize()).fetchResults();


        // 5. 映射查询结果到DTO
        List<DeviceDistributorDTO> records = queryResults.getResults().stream()
                .map(tuple -> {
                    // 提取主表数据
                    TbDeviceDistributor main = tuple.get(qMain);
                    // 提取详情表数据（可能为null，需处理）
                    TbDeviceInfo detail = tuple.get(qDeviceInfo);
                    //  提取详情表数据（可能为null，需处理）
                    TbSysDistributor sysDistributor = tuple.get(qDistributor);
                    // 转换主表数据到DTO
                    DeviceDistributorDTO dto = BeanUtil.copyProperties(main,DeviceDistributorDTO.class);
                    // 补充详情表字段
                    if (detail != null) {
                        dto.setDeviceName(detail.getDeviceName());
                        dto.setModel(detail.getModel());
                        // 其他详情字段...
                    }

                    if (sysDistributor != null) {
                        dto.setDistributorName(sysDistributor.getAcct());
                    }

                    return dto;
                })
                .collect(Collectors.toList());

        return new Paging<>(queryResults.getTotal(),
                records);
    }


    private Predicate buildQueryCondition(String query) {
        return PredicateBuilder.instance()
//                .and(StringUtils.isNotBlank(query.getOrderNo()), ()->
//                        tbSysOrder.orderNo.like(query.getOrderNo()))
//                .and(StringUtils.isNotBlank(query.getNickname()), ()->
//                        tbSysOrder.nickname.eq(query.getNickname()))

                .build();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(DeviceDistributorDetailDTO4Page deviceDistributorDetailDTO) {
// 1. 转换DTO为主表实体
        //TbDeviceDistributor mainEntity = MapstructUtils.convert(deviceDistributorDetailDTO, TbDeviceDistributor.class);

        TbDeviceDistributor mainEntity = BeanUtil.copyProperties(deviceDistributorDetailDTO, TbDeviceDistributor.class);

        // 2. 保存主表数据，获取自动生成的主键ID
        TbDeviceDistributor savedMain = deviceDistributorRepository.save(mainEntity);

        // 3. 转换DTO为详情表实体
        List<TbDeviceDistributorDetail> detailEntitys = new ArrayList<>();
        List<DeviceDistributorChannelDTO> channelDTOS = deviceDistributorDetailDTO.getChannelList();

        for (DeviceDistributorChannelDTO channelDTO:channelDTOS){
            TbDeviceDistributorDetail detail = BeanUtil.copyProperties(channelDTO,TbDeviceDistributorDetail.class);
            detail.setBindId(savedMain.getId()); // 假设详情表外键字段为distributorId
            detailEntitys.add(detail);
        }

        // 5. 保存详情表数据
        deviceDistributorDetailRepository.saveAll(detailEntitys);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void update(DeviceDistributorDetailDTO4Page deviceDistributorDetailDTO) {

        TbDeviceDistributor mainEntity = BeanUtil.copyProperties(deviceDistributorDetailDTO, TbDeviceDistributor.class);

        // 2. 保存主表数据，获取自动生成的主键ID
        TbDeviceDistributor savedMain = deviceDistributorRepository.save(mainEntity);

        // 3. 转换DTO为详情表实体
        List<TbDeviceDistributorDetail> detailEntitys = new ArrayList<>();
        List<DeviceDistributorChannelDTO> channelDTOS = deviceDistributorDetailDTO.getChannelList();

        for (DeviceDistributorChannelDTO channelDTO:channelDTOS){
            TbDeviceDistributorDetail detail = BeanUtil.copyProperties(channelDTO,TbDeviceDistributorDetail.class);
            detail.setBindId(savedMain.getId()); // 假设详情表外键字段为distributorId
            detailEntitys.add(detail);
        }
        // 5. 保存详情表数据
        deviceDistributorDetailRepository.saveAll(detailEntitys);

    }

    @Override
    public DeviceDistributorDetailDTO4Page getDetail(Long bindId) {

        DeviceDistributorDetailDTO4Page detailDTO = new DeviceDistributorDetailDTO4Page();
       Optional<TbDeviceDistributor> optional  =   deviceDistributorRepository.findById(bindId);
       if(optional.isPresent()) {
           TbDeviceDistributor deviceDistributor = optional.get();
           String deviceId = deviceDistributor.getDeviceId();
           if(StringUtils.isNotEmpty(deviceId)) {
               TbDeviceInfo deviceInfo = deviceInfoRepository.findByDeviceId(deviceId);
               detailDTO.setDeviceName(deviceInfo.getDeviceName());
           }

           // 查询所有通道信息
           Predicate channelPredicate = PredicateBuilder.instance()
                   .and(!Objects.isNull(bindId), () ->
                           tbDeviceDistributorDetail.bindId.eq(bindId))
                   .build();


           QueryResults<TbDeviceDistributorDetail> queryResults =
                   jpaQueryFactory.select(tbDeviceDistributorDetail).from(tbDeviceDistributorDetail)
                           .where(channelPredicate).fetchResults();

//            List<DeviceDistributorDetail> details = MapstructUtils
//                    .convert(queryResults.getResults(), DeviceDistributorDetail.class);

           BeanUtil.copyProperties(deviceDistributor, detailDTO);


           List<DeviceDistributorChannelDTO> detailList =
                   BeanUtil.copyToList(queryResults.getResults(), DeviceDistributorChannelDTO.class);
           detailDTO.setChannelList(detailList);
           detailDTO.setDeviceId(deviceId);
       }
        return detailDTO;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(Long bindId) {
        deviceDistributorRepository.deleteById(bindId);
        deviceDistributorDetailRepository.deleteByBindId(bindId);
    }

    @Override
    public DeviceDistributor findByDeviceId(String deviceId) {

        // 查询所有通道信息
        Predicate predicate = PredicateBuilder.instance()
                .and(!Objects.isNull(deviceId), () ->
                        tbDeviceDistributor.deviceId.eq(deviceId))
                .and(tbDeviceDistributor.bindStatus.eq(1))
                .build();

        TbDeviceDistributor tbdistributor =
                jpaQueryFactory.select(tbDeviceDistributor).from(tbDeviceDistributor)
                        .where(predicate).fetchOne();
        DeviceDistributor distributor = new DeviceDistributor();
        BeanUtil.copyProperties(tbdistributor, distributor);
        return distributor;
    }
}
